package com.eastfair.pay.chinaums.BScanC259;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author lqzhou1
 * b扫c支付v4接口,新增上送人行259号文字段
 * 说明：
 * 进行POS通支付操作
 *  测试环境：https://test-api-open.chinaums.com/v4/poslink/transaction/pay
 *  生产环境：https://api-mop.chinaums.com/v4/poslink/transaction/pay
 */
public class Pay {

    static String appid = "10037e6f6823b20801682b6a5e5a0006";
    static String appkey = "1c4e3b16066244ae9b236a09e5b312e8";
    static String url = "https://test-api-open.chinaums.com/v4/poslink/transaction/pay";

    public static void main(String[] args) throws Exception{
        String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); //获取当前时间戳
        String nonce = "nonce"; //签名随机数，长度不超过128
        //1. 组建请求报文
        PayBody reqBody = new PayBody();
        reqBody.merchantCode = "123456789900081";
        reqBody.terminalCode = "00810001";
        reqBody.transactionAmount = 1;
        reqBody.transactionCurrencyCode = "156";
        reqBody.merchantOrderId = "1017"+timestamp;
        reqBody.merchantRemark = "remark";
        reqBody.payMode = "CODE_SCAN";
        reqBody.payCode = "134820585789558821";
        /*↓↓↓↓以下为人行259号文要求新增字段↓↓↓↓*/
        reqBody.deviceType = "11";
        reqBody.serialNum = ""; //deviceType为02、03、04、05、06、08、09或10时，必须填写
        /**
         *deviceType为02、03、04、05、06、08、09或10时,经纬度(longitude、latitude)与cust2必传其一，优先上送经纬度
         *deviceType为01、11、12或13时,经纬度(longitude、latitude)与ip必传其一，优先上送经纬度
         */
        reqBody.longitude = "+26.024749";
        reqBody.latitude = "-119.41755";
        reqBody.cust2 = "{\"locationCode1\":\"value1\",\"lbsNum1\":\"value1\",\"lbsSignal1\":\"value1\",\"locationCode2\":\"value2\",\"lbsNum2\":\"value2\",\"lbsSignal2\":\"value2\",\"locationCode3\":\"value3\",\"lbsNum3\":\"value3\",\"lbsSignal3\":\"value3\"}";
        reqBody.ip = "172.20.11.089";
        reqBody.encryptRandNum = "";
        reqBody.secretText = "";
        reqBody.appVersion = "";
        reqBody.mobileCountryCode = "";
        reqBody.mobileNetNum = "";
        reqBody.location = "";
        reqBody.telecomSysId = "";
        reqBody.telecomNetId = "";
        reqBody.telecomLbs = "";
        reqBody.telecomLbsSignal = "";
        reqBody.iccId = "";
        /*↑↑↑↑以上为人行259号文要求新增字段↑↑↑↑*/
        System.out.println("request body:\n"+reqBody);

        //2. 获取认证报文，timestamp为当前日期，老旧日期无法请求成功
        String authorization = getAuthorization(appid,appkey,timestamp,nonce,reqBody.toString());
        System.out.println("authorization:\n"+authorization);

        //3. 发送http请求，并解析返回信息
        String response = request(url,authorization,reqBody.toString());
        System.out.println("response:\n"+response);
    }

    /**
     * 发送http请求
     * @param url 请求url
     * @param authorization 认证报文
     * @param reqBody  请求体
     * @return response
     */
    static String request(String url, String authorization, String reqBody){
        String response = "";
        PrintWriter out = null;
        BufferedReader in = null;
        try{
            URL realUrl = new URL(url);
            URLConnection conn = realUrl.openConnection();
            HttpURLConnection httpUrlConnection = (HttpURLConnection) conn;
            httpUrlConnection.setRequestProperty("Content-Type", "application/json");
            httpUrlConnection.setRequestProperty("authorization",authorization);
            httpUrlConnection.setDoOutput(true);
            httpUrlConnection.setDoInput(true);
            out = new PrintWriter(httpUrlConnection.getOutputStream());
            out.write(reqBody);
            out.flush();
            httpUrlConnection.connect();
            in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                response += line;
            }
        }catch(Exception e){
            e.printStackTrace();
        } finally {
            try {
                if (out != null) { out.close();}
                if (in != null) {in.close();}
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return response;
    }

    /**
     * 获取签名头
     * @param appid
     * @param appkey
     * @param timestamp 格式:"yyyyMMddHHmmss"
     * @param nonce 随机字符串，
     * @param body 请求体
     * @return authorization 认证报文
     * @throws Exception
     */
    static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception {
        byte[] data = body.getBytes("utf-8");
        InputStream is = new ByteArrayInputStream(data);
        String testSH = DigestUtils.sha256Hex(is);
        String s1 = appid+timestamp+nonce+testSH;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256"));
        byte[] localSignature = mac.doFinal(s1.getBytes("utf-8"));
        String localSignatureStr = Base64.encodeBase64String(localSignature);
        return  "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\"";
    }

    static class PayBody{
        //商户号
        String merchantCode;
        //终端号
        String terminalCode;
        //交易金额
        int transactionAmount;
        //交易币种
        String transactionCurrencyCode;
        //商户订单号
        String merchantOrderId;
        //商户备注
        String merchantRemark;
        //支付方式
        String payMode;
        //支付码
        String payCode;
        //设备类型
        String deviceType;
        //终端硬件序列号
        String serialNum;
        //经度
        String longitude;
        //纬度
        String latitude;
        //基站信息
        String cust2;
        //终端设备IP地址
        String ip;
        //加密随机因子
        String encryptRandNum;
        //硬件序列号密文数据
        String secretText;
        //应用程序版本号
        String appVersion;
        //移动国家代码
        String mobileCountryCode;
        //移动网络号码
        String mobileNetNum;
        //坐标系
        String location;
        //系统识别码
        String telecomSysId;
        //网络识别码
        String telecomNetId;
        //电信基站
        String telecomLbs;
        //电信基站信号
        String telecomLbsSignal;
        //SIM卡卡号
        String iccId;

        String toJson(){
            StringBuilder sb = new StringBuilder();
            sb.append("{");
            if (this.merchantCode != null) sb.append("\"merchantCode\":\"" + this.merchantCode + "\",");
            if (this.terminalCode != null) sb.append("\"terminalCode\":\"" + this.terminalCode + "\",");
            if (this.transactionAmount != 0) sb.append("\"transactionAmount\":\"" + this.transactionAmount + "\",");
            if (this.transactionCurrencyCode != null) sb.append("\"transactionCurrencyCode\":\"" + this.transactionCurrencyCode + "\",");
            if (this.merchantOrderId != null) sb.append("\"merchantOrderId\":\"" + this.merchantOrderId + "\",");
            if (this.merchantRemark != null) sb.append("\"merchantRemark\":\"" + this.merchantRemark + "\",");
            if (this.payMode != null) sb.append("\"payMode\":\"" + this.payMode + "\",");
            if (this.payCode != null) sb.append("\"payCode\":\"" + this.payCode + "\",");
            if (this.deviceType != null) sb.append("\"deviceType\":\"" + this.deviceType + "\",");
            if (this.serialNum != null) sb.append("\"serialNum\":\"" + this.serialNum + "\",");
            if (this.longitude != null) sb.append("\"longitude\":\"" + this.longitude + "\",");
            if (this.latitude != null) sb.append("\"latitude\":\"" + this.latitude + "\",");
            if (this.cust2 != null) sb.append("\"cust2\":\"" + this.cust2 + "\",");
            if (this.ip != null) sb.append("\"ip\":\"" + this.ip + "\",");
            if (this.encryptRandNum != null) sb.append("\"encryptRandNum\":\"" + this.encryptRandNum + "\",");
            if (this.secretText != null) sb.append("\"secretText\":\"" + this.secretText + "\",");
            if (this.appVersion != null) sb.append("\"appVersion\":\"" + this.appVersion + "\",");
            if (this.mobileCountryCode != null) sb.append("\"mobileCountryCode\":\"" + this.mobileCountryCode + "\",");
            if (this.mobileNetNum != null) sb.append("\"mobileNetNum\":\"" + this.mobileNetNum + "\",");
            if (this.location != null) sb.append("\"location\":\"" + this.location + "\",");
            if (this.telecomSysId != null) sb.append("\"telecomSysId\":\"" + this.telecomSysId + "\",");
            if (this.telecomNetId != null) sb.append("\"telecomNetId\":\"" + this.telecomNetId + "\",");
            if (this.telecomLbs != null) sb.append("\"telecomLbs\":\"" + this.telecomLbs + "\",");
            if (this.telecomLbsSignal != null) sb.append("\"telecomLbsSignal\":\"" + this.telecomLbsSignal + "\",");
            if (this.iccId != null) sb.append("\"iccId\":\"" + this.iccId + "\",");

            if (sb.charAt(sb.length() - 1) == ',')
                sb.deleteCharAt(sb.length() - 1);
            sb.append("}");
            return sb.toString();
        }

        public String toString(){
            return this.toJson();
        }

    }

}
